<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>NFT Marketplace</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/web3@1.8.1/dist/web3.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue@3.3.4/dist/vue.global.prod.min.js"></script>
  
  <!-- Tailwind 配置 -->
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#165DFF',
            secondary: '#722ED1',
            accent: '#FF7D00',
            dark: '#1D2129',
            light: '#F2F3F5'
          },
          fontFamily: {
            inter: ['Inter', 'sans-serif'],
          },
        },
      }
    }
  </script>
  
  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .card-hover {
        @apply transition-all duration-300 hover:shadow-xl hover:-translate-y-1;
      }
      .btn-primary {
        @apply bg-primary text-white font-medium py-2 px-4 rounded-lg shadow-md hover:bg-primary/90 transition-all duration-200 focus:ring-2 focus:ring-primary/50 focus:outline-none;
      }
      .btn-secondary {
        @apply bg-white text-primary border border-primary font-medium py-2 px-4 rounded-lg shadow-sm hover:bg-primary/5 transition-all duration-200 focus:ring-2 focus:ring-primary/50 focus:outline-none;
      }
      .input-field {
        @apply w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-primary/50 focus:border-primary outline-none transition-all duration-200;
      }
      .loading-spinner {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100%;
      }
    }
  </style>
</head>
<body class="font-inter bg-light text-dark min-h-screen flex flex-col">
  <div id="app">
    <!-- 导航栏 -->
    <header class="bg-white shadow-sm sticky top-0 z-50">
      <div class="container mx-auto px-4 py-3 flex items-center justify-between">
        <div class="flex items-center space-x-2">
          <i class="fa-brands fa-ethereum text-primary text-2xl"></i>
          <h1 class="text-xl font-bold text-primary">NFT Marketplace</h1>
        </div>
        
        <nav class="hidden md:flex items-center space-x-6">
          <a href="#" class="font-medium hover:text-primary transition-colors" @click="navigateTo('marketplace')">市场</a>
          <a href="#" class="font-medium hover:text-primary transition-colors" @click="navigateTo('my-nfts')">我的NFT</a>
          <a href="#" class="font-medium hover:text-primary transition-colors" @click="navigateTo('create')">创建</a>
        </nav>
        
        <div class="flex items-center space-x-4">
          <button v-if="!connectedAccount" class="btn-primary" @click="connectWallet">
            <i class="fa-solid fa-wallet mr-2"></i>连接钱包
          </button>
          <button v-else class="btn-primary text-sm" @click="showAccountMenu = !showAccountMenu">
            {{ connectedAccount.substring(0, 6) }}...{{ connectedAccount.substring(38) }}
            <i class="fa-solid fa-caret-down ml-1"></i>
          </button>
          <button class="md:hidden text-dark text-xl" @click="showMobileMenu = !showMobileMenu">
            <i :class="showMobileMenu ? 'fa-solid fa-xmark' : 'fa-solid fa-bars'"></i>
          </button>
        </div>
      </div>
      
      <!-- 移动端菜单 -->
      <div v-if="showMobileMenu" class="md:hidden bg-white shadow-md absolute w-full">
        <div class="px-4 py-2 space-y-3">
          <a href="#" class="block py-2 font-medium hover:text-primary transition-colors" @click="navigateTo('marketplace')">市场</a>
          <a href="#" class="block py-2 font-medium hover:text-primary transition-colors" @click="navigateTo('my-nfts')">我的NFT</a>
          <a href="#" class="block py-2 font-medium hover:text-primary transition-colors" @click="navigateTo('create')">创建</a>
        </div>
      </div>
      
      <!-- 账户下拉菜单 -->
      <div v-if="showAccountMenu" class="absolute right-4 top-16 bg-white shadow-lg rounded-lg z-50 w-48">
        <div class="py-2">
          <button class="w-full text-left px-4 py-2 hover:bg-gray-100 transition-colors" @click="disconnectWallet">
            <i class="fa-solid fa-sign-out-alt mr-2"></i>断开连接
          </button>
        </div>
      </div>
    </header>

    <!-- 合约连接设置 -->
    <section class="bg-white rounded-xl shadow-md p-6 card-hover mb-8">
      <h2 class="text-xl font-bold mb-4 flex items-center">
        <i class="fa-solid fa-plug text-primary mr-2"></i>合约连接设置
      </h2>
      
      <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
        <div>
          <label for="contractAddress" class="block text-sm font-medium text-gray-700 mb-1">合约地址</label>
          <input type="text" id="contractAddress" v-model="contractAddress" class="input-field" placeholder="输入NFT合约地址">
        </div>
        <div>
          <label for="contractAbi" class="block text-sm font-medium text-gray-700 mb-1">合约ABI</label>
          <textarea id="contractAbi" v-model="contractAbi" rows="6" class="input-field" placeholder="输入NFT合约ABI (JSON数组)">
[
  {
    "constant": true,
    "inputs": [],
    "name": "getAllListedItems",
    "outputs": [
      {
        "name": "",
        "type": "tuple[]",
        "components": [
          { "name": "tokenId", "type": "uint256" },
          { "name": "seller", "type": "address" },
          { "name": "name", "type": "string" },
          { "name": "description", "type": "string" },
          { "name": "image", "type": "string" },
          { "name": "price", "type": "uint256" },
          { "name": "tokenURI", "type": "string" },
          { "name": "isListed", "type": "bool" }
        ]
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": true,
    "inputs": [],
    "name": "getMyNfts",
    "outputs": [
      {
        "name": "",
        "type": "tuple[]",
        "components": [
          { "name": "tokenId", "type": "uint256" },
          { "name": "seller", "type": "address" },
          { "name": "name", "type": "string" },
          { "name": "description", "type": "string" },
          { "name": "image", "type": "string" },
          { "name": "price", "type": "uint256" },
          { "name": "tokenURI", "type": "string" },
          { "name": "isListed", "type": "bool" }
        ]
      }
    ],
    "payable": false,
    "stateMutability": "view",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      { "name": "name", "type": "string" },
      { "name": "description", "type": "string" },
      { "name": "image", "type": "string" },
      { "name": "tokenURI", "type": "string" },
      { "name": "price", "type": "uint256" }
    ],
    "name": "mintToken",
    "outputs": [ { "name": "", "type": "uint256" } ],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [ { "name": "tokenId", "type": "uint256" } ],
    "name": "buyNft",
    "outputs": [],
    "payable": true,
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [
      { "name": "tokenId", "type": "uint256" },
      { "name": "price", "type": "uint256" }
    ],
    "name": "listItem",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "constant": false,
    "inputs": [ { "name": "tokenId", "type": "uint256" } ],
    "name": "unlistItem",
    "outputs": [],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
  },
  // 此处省略其他方法（完整ABI需包含合约所有方法）
]
          </textarea>
        </div>
      </div>
      
      <div class="flex justify-end mt-6">
        <button class="btn-primary" @click="connectContract" :disabled="connectingContract">
          <i class="fa-solid fa-link mr-2"></i>{{ connectingContract ? '连接中...' : '连接合约' }}
        </button>
      </div>
    </section>

    <!-- 状态显示 -->
    <div v-if="statusMessage" class="mb-6">
      <div :class="statusType === 'success' ? 'bg-green-50 border-l-4 border-green-400' : 'bg-red-50 border-l-4 border-red-400'">
        <div class="p-4">
          <div class="flex">
            <div class="flex-shrink-0">
              <i :class="statusType === 'success' ? 'fa-solid fa-check-circle text-green-500' : 'fa-solid fa-exclamation-circle text-red-500'"></i>
            </div>
            <div class="ml-3">
              <p class="text-sm font-medium" :class="statusType === 'success' ? 'text-green-800' : 'text-red-800'">
                {{ statusMessage }}
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
      <!-- 市场页面 -->
      <div v-if="currentPage === 'marketplace'">
        <div class="flex justify-between items-center mb-6">
          <h2 class="text-2xl font-bold flex items-center">
            <i class="fa-solid fa-store text-primary mr-2"></i>市场
          </h2>
          <div class="flex space-x-3">
            <div class="relative">
              <input type="text" v-model="searchQuery" class="input-field pr-10" placeholder="搜索NFT...">
              <i class="fa-solid fa-search absolute right-3 top-1/2 -translate-y-1/2 text-gray-400"></i>
            </div>
            <select v-model="sortBy" class="input-field bg-white">
              <option value="priceLow">价格从低到高</option>
              <option value="priceHigh">价格从高到低</option>
              <option value="newest">最新上架</option>
              <option value="oldest">最早上架</option>
            </select>
          </div>
        </div>
        
        <div v-if="loadingMarketItems" class="loading-spinner">
          <div class="text-center">
            <i class="fa-solid fa-spinner fa-spin text-primary text-3xl mb-2"></i>
            <p class="text-gray-500">正在加载NFT...</p>
          </div>
        </div>
        
        <div v-else-if="marketItems.length === 0" class="loading-spinner">
          <div class="text-center">
            <i class="fa-solid fa-box-open text-gray-400 text-3xl mb-2"></i>
            <p class="text-gray-500">暂无上架的NFT</p>
          </div>
        </div>
        
        <div v-else class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
          <div v-for="item in filteredMarketItems" :key="item.tokenId" class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
            <div class="relative">
              <img :src="item.image" :alt="item.name" class="w-full h-48 object-cover">
              <div class="absolute top-2 right-2 bg-primary/90 text-white text-xs font-semibold px-2 py-1 rounded">
                {{ item.price }} ETH
              </div>
            </div>
            <div class="p-4">
              <h3 class="font-semibold text-lg mb-1">{{ item.name }}</h3>
              <p class="text-gray-600 text-sm mb-3 line-clamp-2">{{ item.description }}</p>
              <div class="flex justify-between items-center">
                <div class="flex items-center">
                  <i class="fa-solid fa-user-circle text-gray-400 mr-1"></i>
                  <span class="text-xs text-gray-500">{{ item.seller.substring(0, 8) }}...</span>
                </div>
                <button class="btn-primary text-sm" @click="openBuyModal(item)">
                  <i class="fa-solid fa-shopping-cart mr-1"></i>购买
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 创建NFT页面 -->
      <div v-if="currentPage === 'create'">
        <div class="bg-white rounded-xl shadow-md p-6 card-hover">
          <h2 class="text-2xl font-bold mb-6 flex items-center">
            <i class="fa-solid fa-cube text-primary mr-2"></i>铸造NFT
          </h2>
          
          <form @submit.prevent="mintNFT" class="space-y-4">
            <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
              <div>
                <label for="nftName" class="block text-sm font-medium text-gray-700 mb-1">名称</label>
                <input type="text" id="nftName" v-model="nftName" class="input-field" placeholder="输入NFT名称">
              </div>
              <div>
                <label for="nftPrice" class="block text-sm font-medium text-gray-700 mb-1">价格 (ETH)</label>
                <input type="number" id="nftPrice" v-model.number="nftPrice" class="input-field" placeholder="输入价格" min="0.001" step="0.001">
              </div>
              <div class="md:col-span-2">
                <label for="nftDescription" class="block text-sm font-medium text-gray-700 mb-1">描述</label>
                <textarea id="nftDescription" v-model="nftDescription" rows="3" class="input-field" placeholder="输入NFT描述"></textarea>
              </div>
              <div class="md:col-span-2">
                <label for="nftImage" class="block text-sm font-medium text-gray-700 mb-1">图片URL</label>
                <input type="url" id="nftImage" v-model="nftImage" class="input-field" placeholder="输入图片URL">
              </div>
              <div class="md:col-span-2">
                <label for="nftTokenURI" class="block text-sm font-medium text-gray-700 mb-1">Token URI</label>
                <input type="text" id="nftTokenURI" v-model="nftTokenURI" class="input-field" placeholder="输入唯一的Token URI">
              </div>
            </div>
            
            <div class="flex justify-end mt-6">
              <button type="submit" class="btn-primary" :disabled="!contract || mintingNFT">
                <i class="fa-solid fa-magic mr-2"></i>{{ mintingNFT ? '铸造中...' : '铸造并上架' }}
              </button>
            </div>
          </form>
        </div>
      </div>

      <!-- 我的NFT页面 -->
      <div v-if="currentPage === 'my-nfts'">
        <div class="bg-white rounded-xl shadow-md p-6 card-hover mb-6">
          <h2 class="text-2xl font-bold mb-4 flex items-center">
            <i class="fa-solid fa-user-circle text-primary mr-2"></i>我的NFT
          </h2>
          
          <div v-if="loadingMyNFTs" class="loading-spinner">
            <div class="text-center">
              <i class="fa-solid fa-spinner fa-spin text-primary text-3xl mb-2"></i>
              <p class="text-gray-500">正在加载您的NFT...</p>
            </div>
          </div>
          
          <div v-else-if="myNFTs.length === 0" class="loading-spinner">
            <div class="text-center">
              <i class="fa-solid fa-sad-tear text-gray-400 text-3xl mb-2"></i>
              <p class="text-gray-500">您还没有任何NFT</p>
            </div>
          </div>
          
          <div v-else class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
            <div v-for="item in myNFTs" :key="item.tokenId" class="bg-white rounded-xl shadow-md overflow-hidden card-hover">
              <div class="relative">
                <img :src="item.image" :alt="item.name" class="w-full h-48 object-cover">
                <div v-if="item.isListed" class="absolute top-2 right-2 bg-primary/90 text-white text-xs font-semibold px-2 py-1 rounded">
                  {{ item.price }} ETH
                </div>
                <div v-else class="absolute top-2 right-2 bg-gray-500/90 text-white text-xs font-semibold px-2 py-1 rounded">
                  未上架
                </div>
              </div>
              <div class="p-4">
                <h3 class="font-semibold text-lg mb-1">{{ item.name }}</h3>
                <p class="text-gray-600 text-sm mb-3 line-clamp-2">{{ item.description }}</p>
                <button class="btn-secondary text-sm w-full" @click="toggleListing(item)">
                  {{ item.isListed ? '下架' : '上架' }}
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </main>

    <!-- 页脚 -->
    <footer class="bg-dark text-white py-8">
      <div class="container mx-auto px-4">
        <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
          <div>
            <div class="flex items-center space-x-2 mb-4">
              <i class="fa-brands fa-ethereum text-primary text-2xl"></i>
              <h3 class="text-xl font-bold">NFT Marketplace</h3>
            </div>
            <p class="text-gray-400">一个基于以太坊的去中心化NFT市场，让创作和收藏变得简单。</p>
          </div>
          
          <div>
            <h3 class="text-lg font-semibold mb-4">快速链接</h3>
            <ul class="space-y-2">
              <li><a href="#" class="text-gray-400 hover:text-primary transition-colors" @click="navigateTo('marketplace')">市场</a></li>
              <li><a href="#" class="text-gray-400 hover:text-primary transition-colors" @click="navigateTo('create')">创建NFT</a></li>
              <li><a href="#" class="text-gray-400 hover:text-primary transition-colors" @click="navigateTo('my-nfts')">我的收藏</a></li>
              <li><a href="#" class="text-gray-400 hover:text-primary transition-colors">帮助中心</a></li>
            </ul>
          </div>
          
          <div>
            <h3 class="text-lg font-semibold mb-4">联系我们</h3>
            <div class="flex space-x-4 mb-4">
              <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                <i class="fa-brands fa-twitter text-xl"></i>
              </a>
              <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                <i class="fa-brands fa-discord text-xl"></i>
              </a>
              <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                <i class="fa-brands fa-instagram text-xl"></i>
              </a>
              <a href="#" class="text-gray-400 hover:text-primary transition-colors">
                <i class="fa-brands fa-telegram text-xl"></i>
              </a>
            </div>
            <p class="text-gray-400">support@nftmarketplace.com</p>
          </div>
        </div>
        
        <div class="border-t border-gray-800 mt-8 pt-6 text-center text-gray-500">
          <p>&copy; 2025 NFT Marketplace. 保留所有权利。</p>
        </div>
      </div>
    </footer>

    <!-- 购买确认模态框 -->
    <div v-if="buyModalVisible" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
      <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 scale-95 opacity-0" 
           :class="{ 'scale-100 opacity-100': modalTransition }">
        <div class="p-6">
          <div class="flex justify-between items-center mb-4">
            <h3 class="text-xl font-bold">购买NFT</h3>
            <button class="text-gray-400 hover:text-gray-600" @click="closeBuyModal">
              <i class="fa-solid fa-times"></i>
            </button>
          </div>
          
          <div class="mb-6">
            <img :src="selectedItem.image" :alt="selectedItem.name" class="w-full h-48 object-cover rounded-lg mb-4">
            <h4 class="text-lg font-semibold mb-1">{{ selectedItem.name }}</h4>
            <p class="text-gray-600 text-sm mb-3">{{ selectedItem.description }}</p>
            <div class="flex justify-between items-center">
              <div>
                <span class="text-gray-500 text-sm">价格</span>
                <p class="text-xl font-bold text-primary">{{ selectedItem.price }} ETH</p>
              </div>
              <div>
                <span class="text-gray-500 text-sm">卖家</span>
                <p class="text-sm font-medium">{{ selectedItem.seller.substring(0, 8) }}...</p>
              </div>
            </div>
          </div>
          
          <div class="flex justify-end space-x-3">
            <button class="btn-secondary" @click="closeBuyModal">取消</button>
            <button class="btn-primary" @click="buyNFT" :disabled="buyingNFT">
              <i class="fa-solid fa-credit-card mr-2"></i>{{ buyingNFT ? '处理中...' : '确认购买' }}
            </button>
          </div>
        </div>
      </div>
    </div>

    <!-- 上架/下架确认模态框 -->
    <div v-if="listingModalVisible" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
      <div class="bg-white rounded-xl shadow-xl w-full max-w-md mx-4 transform transition-all duration-300 scale-95 opacity-0" 
           :class="{ 'scale-100 opacity-100': modalTransition }">
        <div class="p-6">
          <div class="flex justify-between items-center mb-4">
            <h3 class="text-xl font-bold">{{ currentItem.isListed ? '下架NFT' : '上架NFT' }}</h3>
            <button class="text-gray-400 hover:text-gray-600" @click="closeListingModal">
              <i class="fa-solid fa-times"></i>
            </button>
          </div>
          
          <div class="mb-6">
            <img :src="currentItem.image" :alt="currentItem.name" class="w-full h-48 object-cover rounded-lg mb-4">
            <h4 class="text-lg font-semibold mb-1">{{ currentItem.name }}</h4>
            
            <div v-if="!currentItem.isListed" class="mt-4">
              <label class="block text-sm font-medium text-gray-700 mb-1">价格 (ETH)</label>
              <input type="number" v-model.number="listingPrice" class="input-field" placeholder="输入价格" min="0.001" step="0.001">
            </div>
          </div>
          
          <div class="flex justify-end space-x-3">
            <button class="btn-secondary" @click="closeListingModal">取消</button>
            <button class="btn-primary" @click="handleListing" :disabled="processingListing">
              <i class="fa-solid fa-check mr-2"></i>{{ currentItem.isListed ? '确认下架' : '确认上架' }}
            </button>
          </div>
        </div>
      </div>
    </div>
  </div>

  <script>
    const { createApp } = Vue;
    
    createApp({
      data() {
        return {
          // 合约连接相关
          contractAddress: '',
          contractAbi: '',
          contract: null,
          connectedAccount: null,
          connectingContract: false,
          
          // 页面状态
          currentPage: 'marketplace',
          showMobileMenu: false,
          showAccountMenu: false,
          
          // NFT数据
          marketItems: [],
          myNFTs: [],
          loadingMarketItems: false,
          loadingMyNFTs: false,
          
          // 筛选和排序
          searchQuery: '',
          sortBy: 'priceLow',
          
          // 铸造NFT表单
          nftName: '',
          nftDescription: '',
          nftImage: '',
          nftTokenURI: '',
          nftPrice: 0.1,
          mintingNFT: false,
          
          // 模态框相关
          buyModalVisible: false,
          listingModalVisible: false,
          modalTransition: false,
          selectedItem: null,
          currentItem: null,
          listingPrice: 0.1,
          buyingNFT: false,
          processingListing: false,
          
          // 状态消息
          statusMessage: '',
          statusType: 'success'
        };
      },
      computed: {
        filteredMarketItems() {
          let filtered = this.marketItems.filter(item => 
            item.name.toLowerCase().includes(this.searchQuery.toLowerCase()) || 
            item.description.toLowerCase().includes(this.searchQuery.toLowerCase())
          );
          
          // 排序
          switch(this.sortBy) {
            case 'priceLow':
              return filtered.sort((a, b) => a.price - b.price);
            case 'priceHigh':
              return filtered.sort((a, b) => b.price - a.price);
            case 'newest':
              return filtered.sort((a, b) => b.tokenId - a.tokenId);
            case 'oldest':
              return filtered.sort((a, b) => a.tokenId - b.tokenId);
            default:
              return filtered;
          }
        }
      },
      methods: {
        // 导航
        navigateTo(page) {
          this.currentPage = page;
          this.showMobileMenu = false;
          
          // 加载对应页面的数据
          if (page === 'marketplace') {
            this.fetchAllListedItems();
          } else if (page === 'my-nfts') {
            this.fetchMyNFTs();
          }
        },
        
        // 钱包连接
        async connectWallet() {
          try {
            if (!window.ethereum) {
              this.showStatus('请安装MetaMask钱包', 'error');
              return;
            }
            
            const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
            this.connectedAccount = accounts[0];
            
            // 监听账户变化
            window.ethereum.on('accountsChanged', (accounts) => {
              if (accounts.length === 0) {
                this.connectedAccount = null;
              } else {
                this.connectedAccount = accounts[0];
                if (this.contract) {
                  this.fetchAllListedItems();
                  this.fetchMyNFTs();
                }
              }
            });
            
            this.showStatus('钱包连接成功', 'success');
            
            // 如果已经连接合约，刷新数据
            if (this.contract) {
              this.fetchAllListedItems();
              this.fetchMyNFTs();
            }
          } catch (error) {
            console.error('连接钱包失败:', error);
            this.showStatus('连接钱包失败', 'error');
          }
        },
        
        disconnectWallet() {
          this.connectedAccount = null;
          this.showStatus('钱包已断开连接', 'success');
        },
        
        // 合约连接
        async connectContract() {
          try {
            if (!this.contractAddress || !this.contractAbi) {
              this.showStatus('请输入合约地址和ABI', 'error');
              return;
            }
            
            this.connectingContract = true;
            
            // 解析ABI
            const abi = JSON.parse(this.contractAbi);

            // 校验 ABI 是否包含必要方法
            if (!this.validateABI(abi)) {
              this.connectingContract = false;
              return;
            }

            // 初始化Web3
            if (!window.ethereum) {
              this.showStatus('请安装MetaMask钱包', 'error');
              this.connectingContract = false;
              return;
            }

            const web3 = new Web3(window.ethereum);
            this.contract = new web3.eth.Contract(abi, this.contractAddress);

            // 验证合约是否包含getAllListedItems方法
            if (!this.contract.methods.getAllListedItems) {
              this.showStatus('合约中未找到getAllListedItems方法，请确认ABI是否完整', 'error');
              this.contract = null;
              this.connectingContract = false;
              return;
            }

            this.showStatus('合约连接成功', 'success');
            
            // 如果已连接钱包，加载数据
            if (this.connectedAccount) {
              this.fetchAllListedItems();
              this.fetchMyNFTs();
            }
          } catch (error) {
            console.error('连接合约失败:', error);
            this.showStatus('连接合约失败: ' + error.message, 'error');
            this.contract = null;
          } finally {
            this.connectingContract = false;
          }
        },
        
        // 获取所有上架的NFT
        async fetchAllListedItems() {
          if (!this.contract) {
            this.showStatus('请先连接合约', 'error');
            return;
          }
          
          try {
            this.loadingMarketItems = true;
            const items = await this.contract.methods.getAllListedItems().call();
            
            // 格式化数据
            this.marketItems = items.map(item => ({
              tokenId: parseInt(item.tokenId),
              seller: item.seller,
              name: item.name,
              description: item.description,
              image: item.image,
              price: parseFloat(Web3.utils.fromWei(item.price, 'ether')).toFixed(3),
              tokenURI: item.tokenURI,
              isListed: item.isListed
            }));
            
            this.loadingMarketItems = false;
          } catch (error) {
            console.error('获取市场NFT失败:', error);
            this.showStatus('获取市场NFT失败', 'error');
            this.loadingMarketItems = false;
          }
        },
        
        // 获取我的NFT
        async fetchMyNFTs() {
          if (!this.contract || !this.connectedAccount) {
            this.showStatus('请先连接合约和钱包', 'error');
            return;
          }
          
          try {
            this.loadingMyNFTs = true;
            const items = await this.contract.methods.getMyNfts().call();
            
            // 格式化数据
            this.myNFTs = items.map(item => ({
              tokenId: parseInt(item.tokenId),
              seller: item.seller,
              name: item.name,
              description: item.description,
              image: item.image,
              price: parseFloat(Web3.utils.fromWei(item.price, 'ether')).toFixed(3),
              tokenURI: item.tokenURI,
              isListed: item.isListed
            }));
            
            this.loadingMyNFTs = false;
          } catch (error) {
            console.error('获取我的NFT失败:', error);
            this.showStatus('获取我的NFT失败', 'error');
            this.loadingMyNFTs = false;
          }
        },
        
        // 铸造NFT
        async mintNFT() {
          if (!this.contract || !this.connectedAccount) {
            this.showStatus('请先连接合约和钱包', 'error');
            return;
          }
          
          if (!this.nftName || !this.nftDescription || !this.nftImage || !this.nftTokenURI || this.nftPrice <= 0) {
            this.showStatus('请填写所有必填字段', 'error');
            return;
          }
          
          try {
            this.mintingNFT = true;
            
            // 将价格转换为Wei
            const priceWei = Web3.utils.toWei(this.nftPrice.toString(), 'ether');
            
            // 调用合约方法
            await this.contract.methods
              .mintToken(
                this.nftName,
                this.nftDescription,
                this.nftImage,
                this.nftTokenURI,
                priceWei
              )
              .send({ from: this.connectedAccount });
              
            this.showStatus('NFT铸造成功', 'success');
            
            // 重置表单
            this.nftName = '';
            this.nftDescription = '';
            this.nftImage = '';
            this.nftTokenURI = '';
            this.nftPrice = 0.1;
            
            // 刷新数据
            this.fetchAllListedItems();
            this.fetchMyNFTs();
          } catch (error) {
            console.error('铸造NFT失败:', error);
            this.showStatus('铸造NFT失败: ' + error.message, 'error');
          } finally {
            this.mintingNFT = false;
          }
        },
        
        // 购买NFT
        openBuyModal(item) {
          this.selectedItem = item;
          this.buyModalVisible = true;
          
          // 触发动画
          setTimeout(() => {
            this.modalTransition = true;
          }, 10);
        },
        
        closeBuyModal() {
          this.modalTransition = false;
          setTimeout(() => {
            this.buyModalVisible = false;
            this.selectedItem = null;
          }, 300);
        },
        
        async buyNFT() {
          if (!this.contract || !this.connectedAccount) {
            this.showStatus('请先连接合约和钱包', 'error');
            return;
          }
          
          if (!this.selectedItem) {
            this.closeBuyModal();
            return;
          }
          
          try {
            this.buyingNFT = true;
            
            // 将价格转换为Wei
            const priceWei = Web3.utils.toWei(this.selectedItem.price, 'ether');
            
            // 调用合约方法
            await this.contract.methods
              .buyNft(this.selectedItem.tokenId)
              .send({ from: this.connectedAccount, value: priceWei });
              
            this.showStatus('购买成功', 'success');
            this.closeBuyModal();
            
            // 刷新数据
            this.fetchAllListedItems();
            this.fetchMyNFTs();
          } catch (error) {
            console.error('购买NFT失败:', error);
            this.showStatus('购买NFT失败: ' + error.message, 'error');
          } finally {
            this.buyingNFT = false;
          }
        },
        
        // 上架/下架NFT
        toggleListing(item) {
          this.currentItem = { ...item };
          this.listingPrice = parseFloat(item.price);
          this.listingModalVisible = true;
          
          // 触发动画
          setTimeout(() => {
            this.modalTransition = true;
          }, 10);
        },
        
        closeListingModal() {
          this.modalTransition = false;
          setTimeout(() => {
            this.listingModalVisible = false;
            this.currentItem = null;
            this.listingPrice = 0.1;
          }, 300);
        },
        
        async handleListing() {
          if (!this.contract || !this.connectedAccount) {
            this.showStatus('请先连接合约和钱包', 'error');
            return;
          }
          
          if (!this.currentItem) {
            this.closeListingModal();
            return;
          }
          
          try {
            this.processingListing = true;
            
            if (this.currentItem.isListed) {
              // 下架
              await this.contract.methods
                .unlistItem(this.currentItem.tokenId)
                .send({ from: this.connectedAccount });
              
              this.showStatus('NFT已下架', 'success');
            } else {
              // 上架
              if (this.listingPrice <= 0) {
                this.showStatus('价格必须大于0', 'error');
                this.processingListing = false;
                return;
              }
              
              const priceWei = Web3.utils.toWei(this.listingPrice.toString(), 'ether');
              
              await this.contract.methods
                .listItem(this.currentItem.tokenId, priceWei)
                .send({ from: this.connectedAccount });
              
              this.showStatus('NFT已上架', 'success');
            }
            
            this.closeListingModal();
            
            // 刷新数据
            this.fetchAllListedItems();
            this.fetchMyNFTs();
          } catch (error) {
            console.error('处理NFT状态失败:', error);
            this.showStatus('处理NFT状态失败: ' + error.message, 'error');
          } finally {
            this.processingListing = false;
          }
        },
        
        // 显示状态消息
        showStatus(message, type = 'success') {
          this.statusMessage = message;
          this.statusType = type;
          
          // 3秒后自动隐藏
          setTimeout(() => {
            this.statusMessage = '';
          }, 3000);
        },
        
        validateABI(abi) {
          const requiredMethods = ['getAllListedItems', 'getMyNfts', 'mintToken', 'buyNft'];
          const missingMethods = requiredMethods.filter(method => !abi.some(item => item.name === method));
          
          if (missingMethods.length > 0) {
            this.showStatus(`ABI 缺少以下方法: ${missingMethods.join(', ')}`, 'error');
            return false;
          }
          return true;
        }
      },
      mounted() {
        // 检查是否已安装MetaMask
        if (window.ethereum) {
          // 尝试获取已连接的账户
          window.ethereum.request({ method: 'eth_accounts' })
            .then(accounts => {
              if (accounts.length > 0) {
                this.connectedAccount = accounts[0];
              }
            })
            .catch(error => {
              console.error('获取账户失败:', error);
            });
        }
      }
    }).mount('#app');
  </script>
</body>
</html>